package com.mtw.bbs.article.service.impl;


import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mtw.bbs.constant.TopicConstant;
import com.mtw.bbs.article.mapper.TopicInfoMapper;
import com.mtw.bbs.article.pojo.entity.TopicInfo;
import com.mtw.bbs.article.pojo.entity.TopicMember;
import com.mtw.bbs.article.mapper.TopicMemberMapper;
import com.mtw.bbs.article.service.TopicInfoService;
import com.mtw.bbs.article.service.TopicMemberService;
import com.mtw.bbs.util.ArticleUtils;
import com.mtw.bbs.article.pojo.vo.TopicMemberVo;
import com.mtw.bbs.common.core.util.ExecutorUtilz;
import com.mtw.bbs.common.core.vo.Result;
import com.mtw.bbs.common.redisBase.util.RedisUtilz;
import com.mtw.bbs.common.redisBase.util.TimeUtilz;
import com.mtw.bbs.userAdmin.pojo.dto.UserDto;
import com.mtw.bbs.userAdmin.feign.UserClient;
import com.mtw.bbs.userAdmin.pojo.vo.UserInfoVo;
import jakarta.annotation.Resource;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.DefaultTypedTuple;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * 话题成员
 */
@Slf4j
@RequiredArgsConstructor
@Service("topicMemberService")
public class TopicMemberServiceImpl extends ServiceImpl<TopicMemberMapper, TopicMember> implements TopicMemberService {

    private final UserClient userClient;
    private final ExecutorUtilz executorUtilz;
    private final RedissonClient redissonClient;
    private final TopicInfoMapper topicInfoMapper;
    private final TopicInfoService topicInfoService;
    private final TopicMemberMapper topicMemberMapper;
    private final RedisUtilz<String, String> redisUtilz;


    @Lazy
    @Resource
    private TopicMemberServiceImpl own;


    /**
     * 分页获取话题成员
     *
     * @param page    当前页
     * @param topicId 话题id
     * @return 分页结果
     */
    @Override
    public Page<TopicMemberVo> getTopicMemberPage(int page, int size, String topicId) {


        LambdaQueryWrapper<TopicMember> lqw = new LambdaQueryWrapper<>();
        lqw.select(TopicMember::getId,TopicMember::getUserId,TopicMember::getMemberType);
        lqw.eq(TopicMember::getTopicId, topicId);
        lqw.orderByAsc(TopicMember::getMemberType);
        lqw.orderByDesc(TopicMember::getCreatedDate);
        Page<TopicMember> memberPage = page(new Page<>(page, size), lqw);

        if (CollectionUtil.isEmpty(memberPage.getRecords())) {
            return new Page<>(page, size);
        }


        // 获取用户信息
        Result<List<UserDto>> result = userClient.getUserInfoByIds(memberPage.getRecords().stream().map(TopicMember::getUserId).toArray(String[]::new));
        Map<String, UserInfoVo> posterVoMap = ArticleUtils.getUserInfoVoMap2R(result);
        Page<TopicMemberVo> voPage = new Page<>(page, size);
        voPage.setRecords(memberPage.getRecords().stream().map(x -> {
            TopicMemberVo vo = new TopicMemberVo();
            vo.setId(x.getId());
            vo.setMemberType(x.getMemberType());
            vo.setPoster(posterVoMap.get(x.getUserId()));
            return vo;
        }).toList());

        return voPage;
    }






    /**
     * 用户已加入的话题
     *
     * @param userId 用户id
     * @return 已加入话题的id
     */
    @Override
    public List<TopicMember> getTopicListByUser(String userId) {
        return getTopicListByUser(userId,false);

    }


    /**
     * 用户已加入的话题
     *
     * @param userId 用户id
     * @param needDate 是否需要加入话题时间
     * @return 已加入话题的id
     */
    @Override
    public List<TopicMember> getTopicListByUser(String userId,boolean needDate){

        String key = TopicConstant.REDIS_USER_JOIN_TOPIC_PREFIX + userId;
        Set<ZSetOperations.TypedTuple<String>> set = redisUtilz.reverseRangeWithScores(key, 0, -1);
        // 重建缓存
        if (set == null || needDate) {
            LambdaQueryWrapper<TopicMember> qw = new LambdaQueryWrapper<>();
            if (needDate){
                qw.select(TopicMember::getTopicId,TopicMember::getMemberType,TopicMember::getCreatedDate);
            }else {
                qw.select(TopicMember::getTopicId,TopicMember::getMemberType);
            }
            qw.eq(TopicMember::getUserId, userId);
            List<TopicMember> collect = topicMemberMapper.selectList(qw);
            Set<ZSetOperations.TypedTuple<String>> addSet = new HashSet<>(collect.size());
            for (TopicMember x : collect) {
                ZSetOperations.TypedTuple<String> typedTuple = new DefaultTypedTuple<>(x.getTopicId(), (double) x.getMemberType());
                addSet.add(typedTuple);
            }
            redisUtilz.batchAddZset(key, addSet);
            redisUtilz.expire(key,60+ TimeUtilz.getRandomMinutes(), TimeUnit.MINUTES);
            return collect;
        }

        return set.stream().map(x->{
            TopicMember dto = new TopicMember();
            dto.setTopicId(x.getValue());
            dto.setMemberType(Objects.requireNonNull(x.getScore()).intValue());
            return dto;
        }).toList();
    }


    /**
     * 用户是否已加入话题
     *
     * @param userId  用户id
     * @param topicId 话题id
     * @return 身份类型
     */
    @Override
    @Cacheable(value = "joined",key = "#userId + ':' + #topicId")
    public Integer userJoinedTopic(String userId, String topicId) {

        String key = TopicConstant.REDIS_USER_JOIN_TOPIC_PREFIX + userId;
        if (redisUtilz.hasKey(key)) {
            Double score = redisUtilz.score(key, topicId);
            if (score != null){
                return score.intValue();
            }
        }
        // 查库
        LambdaQueryWrapper<TopicMember> lqw = new LambdaQueryWrapper<>();
        lqw.select(TopicMember::getMemberType);
        lqw.eq(TopicMember::getUserId, userId);
        lqw.eq(TopicMember::getTopicId, topicId);

        TopicMember member = this.getOne(lqw);
        if (member == null){
            return -1;
        }
        redisUtilz.zAdd(key,topicId,member.getMemberType());
        return member.getMemberType();

    }



    /**
     * 更新题主
     *
     * @param userId  用户id
     * @param topicId 话题id
     */
    @Override
    public boolean updateMaster(String userId, String topicId) {

        RLock lock = redissonClient.getLock(TopicConstant.LOCK_TOPIC_PREFIX + topicId);
        lock.lock();
        try {
            redisUtilz.delete(TopicConstant.REDIS_USER_JOIN_TOPIC_PREFIX + userId);
            boolean result = own.doUpdateMaster(userId, topicId);
            if (result){
                executorUtilz.delayedTask(()->redisUtilz.delete(TopicConstant.REDIS_USER_JOIN_TOPIC_PREFIX + userId));
            }
            return result;
        } finally {
            lock.unlock();
        }
    }




    /**
     * 变更话题题主
     *
     * @param userId  新题主userid
     * @param topicId 话题id
     */
    @Transactional
    public boolean doUpdateMaster(String userId, String topicId) {

        // 更新话题的题主
        LambdaUpdateWrapper<TopicInfo> luw = new LambdaUpdateWrapper<>();
        luw.set(TopicInfo::getTopicMaster, userId);
        luw.eq(TopicInfo::getId, topicId);
        boolean updated = topicInfoService.update(luw);
        if (!updated) {
            return false;
        }
        // 旧题主变为成员
        LambdaUpdateWrapper<TopicMember> ouw = new LambdaUpdateWrapper<>();
        ouw.set(TopicMember::getMemberType, TopicConstant.TOPIC_USER);
        ouw.eq(TopicMember::getTopicId, topicId);
        ouw.eq(TopicMember::getMemberType, TopicConstant.TOPIC_MASTER);
        update(ouw);
        // 更新新题主
        LambdaUpdateWrapper<TopicMember> nqw = new LambdaUpdateWrapper<>();
        nqw.set(TopicMember::getMemberType, TopicConstant.TOPIC_MASTER);
        nqw.eq(TopicMember::getUserId, userId);
        nqw.eq(TopicMember::getTopicId, topicId);
        update(nqw);
        return true;
    }


    /**
     * 话题删除题主
     *
     * @param userId  用户id
     * @param topicId 话题id
     */
    @Override
    public boolean deleteMaster(String userId, String topicId) {
        RLock lock = redissonClient.getLock(TopicConstant.LOCK_TOPIC_PREFIX + topicId);
        lock.lock();
        try {
            redisUtilz.delete(TopicConstant.REDIS_USER_JOIN_TOPIC_PREFIX + userId);
            boolean result = own.doDeleteMaster(userId, topicId);
            if (result){
                executorUtilz.delayedTask(()->redisUtilz.delete(TopicConstant.REDIS_USER_JOIN_TOPIC_PREFIX + userId));
            }
            return result;
        } finally {
            lock.unlock();
        }
    }


    /**
     * 变更话题题主
     *
     * @param userId  新题主userid
     * @param topicId 话题id
     */
    @Transactional
    @Caching(evict = {@CacheEvict(value = "joined", key = "#userId +':' + #topicId")})
    public boolean doDeleteMaster(String userId, String topicId) {

        // 旧题主变为成员
        LambdaUpdateWrapper<TopicMember> ouw = new LambdaUpdateWrapper<>();
        ouw.set(TopicMember::getMemberType, TopicConstant.TOPIC_USER);
        ouw.eq(TopicMember::getTopicId, topicId);
        ouw.eq(TopicMember::getUserId, userId);
        ouw.eq(TopicMember::getMemberType, TopicConstant.TOPIC_MASTER);
        boolean updated = update(ouw);
        if (!updated) {
            return false;
        }
        // 更新话题的题主
        LambdaUpdateWrapper<TopicInfo> luw = new LambdaUpdateWrapper<>();
        luw.set(TopicInfo::getTopicMaster, null);
        luw.eq(TopicInfo::getId, topicId);
        return topicInfoService.update(luw);
    }


    /**
     * 用户加入话题
     *
     * @param userId     用户id
     * @param topicId    话题id
     * @param memberType 身份
     */
    @Override
    public boolean joinTopic(String userId, String topicId, Integer memberType) {

        if (TopicConstant.TOPIC_MASTER.equals(memberType)) {
            return false;
        }
        RLock lock = redissonClient.getLock(TopicConstant.LOCK_TOPIC_PREFIX + topicId);
        lock.lock();
        try {
            redisUtilz.delete(TopicConstant.REDIS_USER_JOIN_TOPIC_PREFIX + userId);

            TopicMember member = new TopicMember();
            member.setUserId(userId);
            member.setTopicId(topicId);
            member.setMemberType(memberType);
            member.setCreatedDate(new Date());
            boolean result = own.doAddMember(member);
            if (result) {
                // TODO 发送消息
                executorUtilz.delayedTask(()->redisUtilz.delete(TopicConstant.REDIS_USER_JOIN_TOPIC_PREFIX + userId));
            }
            return result;
        } finally {
            lock.unlock();
        }
    }


    /**
     * 用户加入话题
     */
    @Transactional
    @Caching(evict = {@CacheEvict(value = "joined", key = "#member.userId +':' + #member.topicId")})
    public boolean doAddMember(TopicMember member) {

        // 是否已加入话题
        LambdaQueryWrapper<TopicMember> lqw = new LambdaQueryWrapper<>();
        lqw.eq(TopicMember::getUserId, member.getUserId());
        lqw.eq(TopicMember::getTopicId, member.getTopicId());
        long count = count(lqw);
        if (count > 0) {
            return false;
        }
        boolean saved = save(member);
        if (!saved) {
            return false;
        }
        // 更新话题成员数量
        return topicInfoMapper.updateMemberCount(1, member.getTopicId()) >0;
    }


    /**
     * 更新话题成员身份
     *
     * @param userId   用户id
     * @param topicId  话题id
     * @param identity 身份类型
     */
    @Override
    public boolean updateMemberType(String userId, String topicId, Integer identity) {

        if (TopicConstant.TOPIC_MASTER.equals(identity)) {
            return false;
        }
        RLock lock = redissonClient.getLock(TopicConstant.LOCK_TOPIC_PREFIX + topicId);
        lock.lock();
        try {
            return own.doUpdateMemberType(userId, topicId, identity);
        } finally {
            lock.unlock();
        }
    }


    /**
     * 更新话题成员身份
     *
     * @param userId   用户id
     * @param topicId  话题id
     * @param identity 身份类型
     */
    public boolean doUpdateMemberType(String userId, String topicId, Integer identity) {

        LambdaUpdateWrapper<TopicMember> luw = new LambdaUpdateWrapper<>();
        luw.set(TopicMember::getMemberType, identity);
        luw.eq(TopicMember::getTopicId, topicId);
        luw.eq(TopicMember::getUserId, userId);
        return  update(luw);
    }



    /**
     * 删除话题成员
     *
     * @param userIds   用户id集合
     * @param topicId 话题id
     */
    @Override
    public void deleteMember(Collection<String> userIds, String topicId) {

        if (CollectionUtil.isEmpty(userIds)) {
            return;
        }
        RLock lock = redissonClient.getLock(TopicConstant.LOCK_TOPIC_PREFIX + topicId);
        lock.lock();
        try {
            LambdaQueryWrapper<TopicMember> lqw = new LambdaQueryWrapper<>();
            lqw.in(TopicMember::getUserId, userIds);
            lqw.eq(TopicMember::getTopicId, topicId);
            for (TopicMember member : list(lqw)) {
                redisUtilz.delete(TopicConstant.REDIS_USER_JOIN_TOPIC_PREFIX + member.getUserId());
                boolean result = own.doDeleteMember(member);
                if (result) {
                    executorUtilz.delayedTask(()->redisUtilz.delete(TopicConstant.REDIS_USER_JOIN_TOPIC_PREFIX + member.getUserId()));
                }
            }
        } finally {
            lock.unlock();
        }
    }



    /**
     * 删除话题成员
     */
    @Override
    public void deleteMember(TopicMember member) {

        if (member == null) {
            return;
        }
        RLock lock = redissonClient.getLock(TopicConstant.LOCK_TOPIC_PREFIX + member.getTopicId());
        lock.lock();
        try {
            redisUtilz.delete(TopicConstant.REDIS_USER_JOIN_TOPIC_PREFIX + member.getUserId());
            boolean result = own.doDeleteMember(member);
            if (result) {
                executorUtilz.delayedTask(()->redisUtilz.delete(TopicConstant.REDIS_USER_JOIN_TOPIC_PREFIX + member.getUserId()));
            }
        } finally {
            lock.unlock();
        }
    }


    /**
     * 删除话题成员
     */
    @Transactional
    @Caching(evict = {@CacheEvict(value = "joined", key = "#member.userId + ':' + #member.topicId")})
    public boolean doDeleteMember(TopicMember member) {

        // 删除
        boolean result = removeById(member.getId());
        if (!result) {
            return false;
        }

        if (TopicConstant.TOPIC_MASTER.equals(member.getMemberType())){
            // 更新话题的题主
            LambdaUpdateWrapper<TopicInfo> luw = new LambdaUpdateWrapper<>();
            luw.set(TopicInfo::getTopicMaster, null);
            luw.eq(TopicInfo::getId, member.getTopicId());
            topicInfoService.update(luw);
        }

        // 更新话题成员数量
        topicInfoMapper.updateMemberCount(-1, member.getTopicId());
        return true;
    }





}
